<?php
/*
 * 此文件用于验证短信服务API接口，供开发时参考
 * 执行验证前请确保文件为utf-8编码，并替换相应参数为您自己的信息，并取消相关调用的注释
 * 建议验证前先执行Test.php验证PHP环境
 *
 * 2017/11/30
 */

namespace alisms;

use think\Db;

class AlismsHandler{
    private $accessKeyId = null;
    private $accessKeySecret = null;
    private $_error;
    public function __construct(){
        $this->accessKeyId = "LTAIWApACRXwbC3i";
        $this->accessKeySecret = "TLiMJpsKcADT0KMEK7YkCKi4hgpnTq";
    }

    /**
     * 发送短信
     */
    public function sendSingleSms(String $phone,Array $param,$template_id=1) {
        $template_list = array(
              1 => 'SMS_149385230', //您的验证码为:${code},该验证码15分中有效，请勿泄露他人
//            2 => 'SMS_108405072', //验证码${code}，您正在尝试修改登录密码，请妥善保管账户信息。
//            3 => 'SMS_108405073', //验证码${code}，您正在注册成为新用户，感谢您的支持！
//            4 => 'SMS_108405074', //验证码${code}，您正尝试异地登录，若非本人操作，请勿泄露。
//            5 => 'SMS_108405075', //验证码${code}，您正在登录，若非本人操作，请勿泄露
//            7 => 'SMS_108405077', //验证码${code}，您正在进行身份验证，打死不要告诉别人哦！
//            8 => 'SMS_134240343', //您已经成功预约了${shop_name}的${service}服务，请于${time}准时到店，凭手机号享受服务。谢谢！
//            9 => 'SMS_135027413', //您于${time}消费金额${money}元。订单号：${order_no}，当前账号余额${total}元
//            10 => 'SMS_135032220', //您充值的${money}元已到账，充值时间：${time}，当前账号余额${total}元
//            11 => 'SMS_134316830', //验证码${code}，您正在进行手机验证，若非本人操作，请勿泄露
//            12 => 'SMS_137673397', //支付成功通知，您在${shop_name}购买的订单${order_no}已成功支付，感谢您的支持！
//            13 => 'SMS_137658415', //您在${shop_name}的订单${order_no}已经使用${express}发货啦！快递单号${send_no}，感谢您的支持！
//            14 => 'SMS_137688392', //您在${shop_name}的订单${order_no}已成功发起退款，售后单号${service_no}，请及时更进进度，感谢您的支持！
//            15 => 'SMS_137668353', //很抱歉，您在${shop_name}的退款申请未被同意，售后单号${service_no}，如有疑问请及时与商家联系，感谢您的支持！
//            16 => 'SMS_140726900', // 你于${time}核销订单成功，订单号：${order_no}。
//            17 => 'SMS_140726901', // 你于${time}核销订单成功，订单号：${order_no}，该卡剩余次数为${num}次。


        );
        /*
            短信验证码 ：使用同一个签名，对同一个手机号码发送短信验证码，1条/分钟，5条/小时，10条/天。一个手机号码通过阿里云短信服务平台只能收到40条/天。（天的计算方式是是当下时间往后推24小时，例如2017年8月24日：11:00发送一条验证码短信，计算限流方式是2017年8月23日11:00点到8月24日：11:00点，是否满40条）如您是在发送验证码时提示业务限流，建议您根据以上业务调整接口调用时间

            短信通知： 使用同一个签名和同一个短信模板ID，对同一个手机号码发送短信通知，支持50条/日（天的计算方式是是当下时间往后推24小时，例如2017年8月24日：11:00发送一条短信，计算限流方式是2017年8月23日11:00点到8月24日：11:00点，是否满50条）。如您是在发送验证码时提示业务限流，建议您根据以上业务调整接口调用时间；

            推广短信： 使用同一个签名和同一个短信模板ID，对同一个手机号码发送短信通知，支持50条/日（天的计算方式是是当下时间往后推24小时，例如2017年8月24日：11:00发送一条短信，计算限流方式是2017年8月23日11:00点到8月24日：11:00点，是否满50条）。如您是在发送验证码时提示业务限流，建议您根据以上业务调整接口调用时间；；
         */
        $template_type_list = [
            'code' => [1,2,3,4,5,7,11],   //短信验证码
            'notify' => [9,10,12,13,14,15,16,17],  //短信通知
            'promotion' => []   //推广短信
        ];
        $template_type = null; //短信类型
        foreach ($template_type_list as $type => $template_ids) {
            if(in_array($template_id,$template_ids)){
                //判断模版id是否存在
                $template_type = $type;
                break;
            }
        }
        if (!$template_type) {
            //模版id不存在
            $this->_error = 'not this sms_template!';
            return ['status' => 0,'msg' => $this->_error];
        }
        if ($template_type == 'code') {
            //短信验证码
            $check = $this->beforeSendCheck($phone);
            if(!$check){
                return ['status'=>0,'msg'=>'短信发送间隔不能少于60秒'];
            }
        }

        $params = [];

        // fixme 必填: 短信接收号码
        $params["PhoneNumbers"] = $phone;

        // fixme 必填: 短信签名，应严格按"签名名称"填写，请参考: https://dysms.console.aliyun.com/dysms.htm#/develop/sign
        $params["SignName"] = "佛山市仙果科技有限公司";

        // fixme 必填: 短信模板Code，应严格按"模板CODE"填写, 请参考: https://dysms.console.aliyun.com/dysms.htm#/develop/template
        $params["TemplateCode"] = $template_list[$template_id];
        // fixme 可选: 设置模板参数, 假如模板中存在变量需要替换则为必填项
        $params['TemplateParam'] = $param;

        // fixme 可选: 设置发送短信流水号
        // $params['OutId'] = "12345";

        // fixme 可选: 上行短信扩展码, 扩展码字段控制在7位或以下，无特殊需求用户请忽略此字段
        // $params['SmsUpExtendCode'] = "1234567";

        // *** 需用户填写部分结束, 以下代码若无必要无需更改 ***
        if(!empty($params["TemplateParam"]) && is_array($params["TemplateParam"])) {
            $params["TemplateParam"] = json_encode($params["TemplateParam"], JSON_UNESCAPED_UNICODE);
        }
        $res = $this->doRequest($params,"SendSms");
        if($res !== false){
            $res = json_decode(json_encode($res),true);
        }else{
            $return = ['status'=>0,'msg'=>'暂无法发送短信'];
        }
        if($res['Code']=='OK'){
            $return = ['status'=>1,'msg'=>'发送成功'];
        }else{
            // $return = ['status'=>0,'msg'=>$res['Message']];
            $return = ['status'=>0,'msg'=>'短信发送过于频繁，请稍后再试'];
        }
        $content = $this->parseTemplate($template_id,$param,$params["SignName"]);
        $save = [
            'web_id'  => config('web_id')??0,
            'lang_id' => 1,
            'phone'   => $phone,
            'content' => $content,
            'status'  => $return['status'],
            'remark'  => $return['msg']??'未知错误',
            'addtime' => request()->time(),
            'sendtime'=> request()->time(),
        ];
        Db::name("SmsLog")->insert($save);
        return $return;
    }

    public function sendBatchSms($template_id,$phone,$param) {

        $params = array ();

        // *** 需用户填写部分 ***

        // fixme 必填: 请参阅 https://ak-console.aliyun.com/ 取得您的AK信息
        $accessKeyId = "your access key id";
        $accessKeySecret = "your access key secret";

        // fixme 必填: 待发送手机号。支持JSON格式的批量调用，批量上限为100个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式
        $params["PhoneNumberJson"] = array(
            "1500000000",
            "1500000001",
        );

        // fixme 必填: 短信签名，支持不同的号码发送不同的短信签名，每个签名都应严格按"签名名称"填写，请参考: https://dysms.console.aliyun.com/dysms.htm#/develop/sign
        $params["SignNameJson"] = array(
            "云通信",
            "云通信2",
        );

        // fixme 必填: 短信模板Code，应严格按"模板CODE"填写, 请参考: https://dysms.console.aliyun.com/dysms.htm#/develop/template
        $params["TemplateCode"] = "SMS_1000000";

        // fixme 必填: 模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为
        // 友情提示:如果JSON中需要带换行符,请参照标准的JSON协议对换行符的要求,比如短信内容中包含\r\n的情况在JSON中需要表示成\\r\\n,否则会导致JSON在服务端解析失败
        $params["TemplateParamJson"] = array(
            array(
                "name" => "Tom",
                "code" => "123",
            ),
            array(
                "name" => "Jack",
                "code" => "456",
            ),
        );

        // todo 可选: 上行短信扩展码, 扩展码字段控制在7位或以下，无特殊需求用户请忽略此字段
        // $params["SmsUpExtendCodeJson"] = json_encode(array("90997","90998"));


        // *** 需用户填写部分结束, 以下代码若无必要无需更改 ***
        $params["TemplateParamJson"]  = json_encode($params["TemplateParamJson"], JSON_UNESCAPED_UNICODE);
        $params["SignNameJson"] = json_encode($params["SignNameJson"], JSON_UNESCAPED_UNICODE);
        $params["PhoneNumberJson"] = json_encode($params["PhoneNumberJson"], JSON_UNESCAPED_UNICODE);

        if(!empty($params["SmsUpExtendCodeJson"] && is_array($params["SmsUpExtendCodeJson"]))) {
            $params["SmsUpExtendCodeJson"] = json_encode($params["SmsUpExtendCodeJson"], JSON_UNESCAPED_UNICODE);
        }

        // 此处可能会抛出异常，注意catch
        $content = $this->doRequest($params,"SendBatchSms");

        return $content;
    }

    /**
     * 短信发送记录查询
    */
    public function querySendDetails() {

        $params = [];

        // *** 需用户填写部分 ***

        // fixme 必填: 短信接收号码
        $params["PhoneNumber"] = "17000000000";

        // fixme 必填: 短信发送日期，格式Ymd，支持近30天记录查询
        $params["SendDate"] = "20170710";

        // fixme 必填: 分页大小
        $params["PageSize"] = 10;

        // fixme 必填: 当前页码
        $params["CurrentPage"] = 1;

        // fixme 可选: 设置发送短信流水号
        $params["BizId"] = "yourBizId";

        $content = $this->doRequest($params,"QuerySendDetails");
    }

    private function doRequest($params,$action){
        // 初始化SignatureHelper实例用于设置参数，签名以及发送请求
        $helper = new SignatureHelper();
        // 此处可能会抛出异常，注意catch
        $content = $helper->request(
            $this->accessKeyId,
            $this->accessKeySecret,
            "dysmsapi.aliyuncs.com",
            array_merge($params, array(
                "RegionId" => "cn-hangzhou",
                "Action" => $action,
                "Version" => "2017-05-25",
            ))
        );
        return $content;
    }

    private function parseTemplate($template_id,$param,$SignName=''){
        $template_list = [
            1 => '验证码${code}，您正在进行身份验证，打死不要告诉别人哦！',
//            1 => '验证码${code}，您正在尝试变更重要信息，请妥善保管账户信息。',
//            2 => '验证码${code}，您正在尝试修改登录密码，请妥善保管账户信息。',
//            3 => '验证码${code}，您正在注册成为新用户，感谢您的支持！',
//            4 => '验证码${code}，您正尝试异地登录，若非本人操作，请勿泄露。',
//            5 => '验证码${code}，您正在登录，若非本人操作，请勿泄露!',
//            8 => '您已经成功预约了${shop_name}的${service}服务，请于${time}准时到店，凭手机号享受服务。谢谢！',
//            9 => '您于${time}消费金额${money}元。订单号：${order_no}，当前账号余额${total}',
//            10 => '您充值的${money}元已到账，充值时间：${time}，当前账号余额${total}',
//            11 => '验证码${code}，您正在进行手机验证，若非本人操作，请勿泄露！',
        ];
        if(!empty($template_list[$template_id])){
            $content = $template_list[$template_id];
            foreach ($param as $key => $value) {
                $content = str_replace('${'.$key.'}',$value,$content);
            }
            return "【{$SignName}】".$content;
        }else{
            return "保密信息";
        }
    }

    /**
     * 发送验证码
     * @param  [type]  $phone      [description]
     * @param  integer $limit_time [description]
     * @return [type]              [description]
     */
    private function beforeSendCheck($phone,$limit_time=60){
        $valid_addtime = request()->time()-$limit_time;
        return Db::name('SmsLog')->where(['phone'=>$phone,'addtime'=>['gt',$valid_addtime]])->count()?false:true;
    }

    //获取错误信息
    public function getError(){
        return $this->_error;
    }
}
